Micron Document
pintobyte rngit

Node / public / precursor-lxmfchat.git / files / xous-core / tools / src / git_remote_version.rs

Displaying Raw • Download

xous-core/tools/src/git_remote_version.rs main (17e4bce8) Text, 5.54 KB

// This code is noted as an option we could pull into the tool set, but the problem with it is
// that its dependence on \\`reqwest\\` to interface with github to try and guess semantic versions
// pulls a huge amount of code into the dependency tree that I prefer not to have in the SBOM.
// Thus to get a semantic version users have to either check out tags, assign a version manually,
// or just go with a nil-rev on the versioning.

use std::collections::HashMap;
use std::fs;

use anyhow::{Context, Result};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct CargoToml {
dependencies: Option<HashMap<String, Dependency>>,
}

#[derive(Debug, Deserialize, Clone)]
#[serde(untagged)]
enum Dependency {
Simple(String),
Detailed(DetailedDependency),
}

#[derive(Debug, Deserialize, Clone)]
struct DetailedDependency {
git: Option<String>,
rev: Option<String>,
}

#[derive(Debug, Deserialize)]
struct GitHubTag {
name: String,
}

fn find_xous_core_revision(cargo_toml_path: &str) -> Result<Option<String>> {
// Read and parse Cargo.toml
let contents = fs::read_to_string(cargo_toml_path).context("Failed to read Cargo.toml")?;

let cargo: CargoToml = toml::from_str(&contents).context("Failed to parse Cargo.toml")?;

let Some(deps) = cargo.dependencies else {
return Ok(None);
};

let xous_core_url = "https://github.com/betrusted-io/xous-core";
let mut found_revisions = Vec::new();

// Search through dependencies for xous-core references
for (name, dep) in deps.iter() {
if let Dependency::Detailed(detailed) = dep {
if let (Some(git), Some(rev)) = (&detailed.git, &detailed.rev) {
if git == xous_core_url || git == &format!("{}.git", xous_core_url) {
found_revisions.push((name.clone(), rev.clone()));
}
}
} else if let Dependency::Simple(simple) = dep {
unimplemented!("Can't handle dep: {}", simple);
}
}

if found_revisions.is_empty() {
return Ok(None);
}

if found_revisions.len() > 1 {
eprintln!("Warning: Found multiple xous-core revisions:");
for (name, rev) in &found_revisions {
eprintln!(" {} -> {}", name, rev);
}
eprintln!("Using the first one: {}", found_revisions[0].1);
}

Ok(Some(found_revisions[0].1.clone()))
}

fn get_latest_tag_from_github(repo: &str) -> Result<String> {
let url = format!("https://api.github.com/repos/{}/tags", repo);

let client = reqwest::blocking::Client::builder()
.user_agent("xous-app-uf2-tool") // GitHub requires a user agent
.build()?;

let mut request = client.get(&url);

// Optional: use token if available (no token required by default)
let using_token = if let Ok(token) = std::env::var("GITHUB_TOKEN") {
request = request.header("Authorization", format!("token {}", token));
true
} else {
false
};

let response = request.send().context("Failed to fetch tags from GitHub")?;

// Check for rate limit errors
if response.status() == reqwest::StatusCode::FORBIDDEN {
// Check if this is a rate limit error
if let Some(remaining) = response.headers().get("x-ratelimit-remaining") {
if remaining.to_str().unwrap_or("") == "0" {
if using_token {
anyhow::bail!(
"GitHub API rate limit exceeded (5000 requests/hour with token).\\n\\
Please wait before trying again."
);
} else {
anyhow::bail!(
"GitHub API rate limit exceeded (60 requests/hour per IP without authentication).\\n\\
\\n\\
To increase your rate limit to 5000 requests/hour, set the GITHUB_TOKEN environment variable:\\n\\
\\n\\
1. Create a GitHub Personal Access Token at:\\n\\
https://github.com/settings/tokens\\n\\
2. No special permissions needed - you can leave all scopes unchecked\\n\\
3. Set the token:\\n\\
Linux/Mac: export GITHUB_TOKEN=your_token_here\\n\\
Windows: set GITHUB_TOKEN=your_token_here\\n\\
\\n\\
For more info: https://docs.github.com/en/rest/overview/rate-limits-for-the-rest-api"
);
}
}
}
}

if !response.status().is_success() {
anyhow::bail!("GitHub API request failed: {}", response.status());
}

let tags: Vec<GitHubTag> = response.json().context("Failed to parse GitHub API response")?;

tags.first().map(|tag| tag.name.clone()).ok_or_else(|| anyhow::anyhow!("No tags found in repository"))
}

pub fn get_xous_version() -> Result<String> {
// Assume we're running in the root directory
let cargo_toml_path = "Cargo.toml";

println!("Parsing {} for xous-core dependencies...", cargo_toml_path);

let rev = find_xous_core_revision(cargo_toml_path)?
.ok_or_else(|| anyhow::anyhow!("No xous-core git dependency found in Cargo.toml"))?;

println!("Found xous-core revision: {}", rev);
println!("Fetching latest tag from GitHub...");

let version = get_latest_tag_from_github("betrusted-io/xous-core")?;

println!("Latest xous-core version: {}", version);

Ok(version)
}

Served by rngit 1.4.0 - Generated in 0.05s